#ifndef __UESDK_USER_MANGER_H__
#define __UESDK_USER_MANGER_H__

#include "uesdk/config.h"
#include <boost/smart_ptr.hpp>
#include <boost/any.hpp>
#include <map>
#include "uesdk/mutex.h"
#include "uesdk/singleton.h"
#include <vector>

#define UETHIRDLOGINQQ 1
#define UETHIRDLOGINWECHAT 2

namespace uesdk{

enum VerifyType{
    VERIFY_DEFAULT = 0,
    VERIFY_REGISTER ,
    VERIFY_LOGIN,
    VERIFY_RESETPASSWORD,
};

char * VerifyTypeToString(VerifyType type){
    switch(type){
        case VerifyType::VERIFY_DEFAULT:
            return "default";
        case VerifyType::VERIFY_REGISTER:
            return "register";
        case VerifyType::VERIFY_LOGIN:
            return "login";
        case VerifyType::VERIFY_RESETPASSWORD:
            return "resetpassword";
        default:
            return "error";
    }
}

enum ThirdPlateName{
    THIRD_ERROR = -1,
    THIRD_QQ = 0,
    THIRD_WECHAT,
};

char* ThirdPlateToString(ThirdPlateName type){
    switch(type){
        case ThirdPlateName::THIRD_QQ:
            return "QQ";
        case ThirdPlateName::THIRD_WECHAT:
            return "WECHAT";
        default:
            return "error";
    }
}

ThirdPlateName StringToThirdPlate(const char* name){
#define XX(type,m) \
    if(stricmp(name,#m)==0) { \
        return ThirdPlateName::type; \
    }

    XX(THIRD_QQ,QQ);
    XX(THIRD_WECHAT,WECHAT);

    return ThirdPlateName::THIRD_ERROR;

}



class UESDK_DLL_API User{
public:
    typedef boost::shared_ptr<User> ptr;
    typedef Mutex MutexType;

    User(int32_t id);

    template<class T>
    void setData(const std::string& key,const T& v){
        MutexType::Lock lock(m_mutex);
        m_data[key] = v;
    }
    
    template<class T>
    T getData(const std::string& key,const T& def= T()){
        MutexType::Lock lock(m_mutex);
		std::map<std::string, boost::any>::iterator it =  m_data.find(key);
        if(it==m_data.end()){
            return def;
        }
        boost::any v = it->second;
        lock.unlock();
        try{
            return boost::any_cast<T>(v);
        }catch(...){
        }
        return def;
    }

    void del(const std::string& key);
    bool has(const std::string& key);

    int32_t getId() const {return m_id;}
    void setId(int32_t id) {m_id = id;}

    bool getSelfUserMessage();
    bool getNewToken();
    bool isTokenExpire();

    /**
     * @brief Check whether the token expires. If it expires, get a new token
     * 
     * @param force force direct refresh 
     * @return true token is available
     * @return false token not available
     */
    bool checkAndRefreshToken(bool force  = false);


private:
    MutexType m_mutex;
    int32_t m_id;
    std::map<std::string,boost::any> m_data;
};



class UESDK_DLL_API UserManger {
public:
    typedef boost::shared_ptr<UserManger> ptr;
    typedef Mutex MutexType;

    void add(User::ptr data);
    void del(int32_t id);
    void del(std::vector<int32_t>& ids);
    User::ptr get(int32_t id);

    static User::ptr login(const std::string& user_name,const std::string& password);
    static User::ptr loginByVerifyTel(const std::string& tel,const std::string& verifyCode);
    static User::ptr loginByFlashToken(const std::string& flashToken);
    static User::ptr thirdLogin(const std::string& third_name);
    static bool phoneSmsVerify(const std::string& phone,VerifyType type = VerifyType::VERIFY_DEFAULT);
    static bool emailSmsVerify(const std::string& email,VerifyType type = VerifyType::VERIFY_DEFAULT);
    static User::ptr thirdLoginCheck(const std::string& third_name, const std::string& code,const std::string& verifyCode);



    static bool createUserByTel(const std::string& user_name,const std::string& password,const std::string& tel,const std::string& verifyCode);
    static bool createUserByEmail(const std::string& user_name,const std::string& password,const std::string& email,const std::string& verifyCode);
    

private:
    MutexType m_mutex;
    std::map<int32_t,User::ptr> m_data;
};

typedef Singleton<UserManger> UserMgr;

}




#endif